﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Giant.Admin.Extensions;
using Giant.Admin.Models.Common;
using Giant.Admin.Models.Settings;
using Giant.Admin.Models.Sites;
using Giant.Core;
using Giant.Core.Domain;
using Giant.Core.Domain.Common;
using Giant.Core.Domain.Users;
using Giant.Core.Domain.Localization;
using Giant.Core.Domain.Media;
using Giant.Core.Domain.News;
using Giant.Core.Domain.Security;
using Giant.Core.Domain.Seo;
using Giant.Services;
using Giant.Services.Common;
using Giant.Services.Configuration;
using Giant.Services.Users;
using Giant.Services.Helpers;
using Giant.Services.Localization;
using Giant.Services.Logging;
using Giant.Services.Media;
using Giant.Services.Security;
using Giant.Services.Sites;
using Giant.Web.Framework;
using Giant.Web.Framework.Controllers;
using Giant.Web.Framework.Kendoui;
using Giant.Web.Framework.Localization;
using Giant.Web.Framework.Mvc;
using Giant.Web.Framework.Security;
using Giant.Web.Framework.Security.Captcha;
using Giant.Web.Framework.Themes;

namespace Giant.Admin.Controllers
{
    public partial class SettingController : BaseAdminController
	{
		#region Fields

        private readonly ISettingService _settingService;
        private readonly IPictureService _pictureService;
        private readonly ILocalizationService _localizationService;
        private readonly IDateTimeHelper _dateTimeHelper;
        private readonly IEncryptionService _encryptionService;
        private readonly IThemeProvider _themeProvider;
        private readonly IUserService _userService;
        private readonly IUserActivityService _userActivityService;
        private readonly IPermissionService _permissionService;
        private readonly IMaintenanceService _maintenanceService;
        private readonly ISiteService _siteService;
        private readonly IWorkContext _workContext;
        private readonly IGenericAttributeService _genericAttributeService;
        private readonly ILanguageService _languageService;
        private readonly ILocalizedEntityService _localizedEntityService;

        #endregion

        #region Constructors

        public SettingController(ISettingService settingService,
            IPictureService pictureService, 
            ILocalizationService localizationService, 
            IDateTimeHelper dateTimeHelper,
            IEncryptionService encryptionService,
            IThemeProvider themeProvider,
            IUserService userService, 
            IUserActivityService userActivityService,
            IPermissionService permissionService,
            IMaintenanceService maintenanceService,
            ISiteService siteService,
            IWorkContext workContext, 
            IGenericAttributeService genericAttributeService,
            ILanguageService languageService,
            ILocalizedEntityService localizedEntityService)
        {
            this._settingService = settingService;
            this._pictureService = pictureService;
            this._localizationService = localizationService;
            this._dateTimeHelper = dateTimeHelper;
            this._encryptionService = encryptionService;
            this._themeProvider = themeProvider;
            this._userService = userService;
            this._userActivityService = userActivityService;
            this._permissionService = permissionService;
            this._maintenanceService = maintenanceService;
            this._siteService = siteService;
            this._workContext = workContext;
            this._genericAttributeService = genericAttributeService;
            this._languageService = languageService;
            this._localizedEntityService = localizedEntityService;
        }

        #endregion
        
        #region Methods

        [ChildActionOnly]
        public ActionResult Mode(string modeName = "settings-advanced-mode")
        {
            var model = new ModeModel()
            {
                ModeName = modeName,
                Enabled = _workContext.CurrentUser.GetAttribute<bool>(modeName)
            };
            return PartialView(model);
        }

        [ChildActionOnly]
        public ActionResult SiteScopeConfiguration()
        {
            var allSites = _siteService.GetAllSites();
            if (allSites.Count < 2)
                return Content("");

            var model = new SiteScopeConfigurationModel();
            foreach (var s in allSites)
            {
                model.Sites.Add(new SiteModel
                {
                    Id = s.Id,
                    Name = s.Name
                });
            }
            model.SiteId = this.GetActiveSiteScopeConfiguration(_siteService, _workContext);

            return PartialView(model);
        }
        public ActionResult ChangeSiteScopeConfiguration(int siteid, string returnUrl = "")
        {
            var site = _siteService.GetSiteById(siteid);
            if (site != null || siteid == 0)
            {
                _genericAttributeService.SaveAttribute(_workContext.CurrentUser,
                    SystemUserAttributeNames.AdminAreaSiteScopeConfiguration, siteid);
            }

            //home page
            if (String.IsNullOrEmpty(returnUrl))
                returnUrl = Url.Action("Index", "Home", new { area = "Admin" });
            //prevent open redirection attack
            if (!Url.IsLocalUrl(returnUrl))
                return RedirectToAction("Index", "Home", new { area = "Admin" });
            return Redirect(returnUrl);
        }

        public ActionResult News()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            //load settings for a chosen site scope
            var siteScope = this.GetActiveSiteScopeConfiguration(_siteService, _workContext);
            var newsSettings = _settingService.LoadSetting<NewsSettings>(siteScope);
            var model = newsSettings.ToModel();
            model.ActiveSiteScopeConfiguration = siteScope;
            if (siteScope > 0)
            {
                model.Enabled_OverrideForSite = _settingService.SettingExists(newsSettings, x => x.Enabled, siteScope);
                model.AllowNotRegisteredUsersToLeaveComments_OverrideForSite = _settingService.SettingExists(newsSettings, x => x.AllowNotRegisteredUsersToLeaveComments, siteScope);
                model.NotifyAboutNewNewsComments_OverrideForSite = _settingService.SettingExists(newsSettings, x => x.NotifyAboutNewNewsComments, siteScope);
                model.ShowNewsOnMainPage_OverrideForSite = _settingService.SettingExists(newsSettings, x => x.ShowNewsOnMainPage, siteScope);
                model.MainPageNewsCount_OverrideForSite = _settingService.SettingExists(newsSettings, x => x.MainPageNewsCount, siteScope);
                model.NewsArchivePageSize_OverrideForSite = _settingService.SettingExists(newsSettings, x => x.NewsArchivePageSize, siteScope);
                model.ShowHeaderRssUrl_OverrideForSite = _settingService.SettingExists(newsSettings, x => x.ShowHeaderRssUrl, siteScope);
            }
            return View(model);
        }
        [HttpPost]
        public ActionResult News(NewsSettingsModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            //load settings for a chosen site scope
            var siteScope = this.GetActiveSiteScopeConfiguration(_siteService, _workContext);
            var newsSettings = _settingService.LoadSetting<NewsSettings>(siteScope);
            newsSettings = model.ToEntity(newsSettings);

            /* We do not clear cache after each setting update.
             * This behavior can increase performance because cached settings will not be cleared 
             * and loaded from database after each update */
            _settingService.SaveSettingOverridablePerSite(newsSettings, x => x.Enabled, model.Enabled_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(newsSettings, x => x.AllowNotRegisteredUsersToLeaveComments, model.AllowNotRegisteredUsersToLeaveComments_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(newsSettings, x => x.NotifyAboutNewNewsComments, model.NotifyAboutNewNewsComments_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(newsSettings, x => x.ShowNewsOnMainPage, model.ShowNewsOnMainPage_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(newsSettings, x => x.MainPageNewsCount, model.MainPageNewsCount_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(newsSettings, x => x.NewsArchivePageSize, model.NewsArchivePageSize_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(newsSettings, x => x.ShowHeaderRssUrl, model.ShowHeaderRssUrl_OverrideForSite, siteScope, false);
            
            //now clear settings cache
            _settingService.ClearCache();


            //activity log
            _userActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings"));

            SuccessNotification(_localizationService.GetResource("Admin.Configuration.Updated"));
            return RedirectToAction("News");
        }


       
        public ActionResult Media()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            //load settings for a chosen site scope
            var siteScope = this.GetActiveSiteScopeConfiguration(_siteService, _workContext);
            var mediaSettings = _settingService.LoadSetting<MediaSettings>(siteScope);
            var model = mediaSettings.ToModel();
            model.ActiveSiteScopeConfiguration = siteScope;
            if (siteScope > 0)
            {
                model.AvatarPictureSize_OverrideForSite = _settingService.SettingExists(mediaSettings, x => x.AvatarPictureSize, siteScope);
                model.MaximumImageSize_OverrideForSite = _settingService.SettingExists(mediaSettings, x => x.MaximumImageSize, siteScope);
                model.MultipleThumbDirectories_OverrideForSite = _settingService.SettingExists(mediaSettings, x => x.MultipleThumbDirectories, siteScope);
                model.DefaultImageQuality_OverrideForSite = _settingService.SettingExists(mediaSettings, x => x.DefaultImageQuality, siteScope);
            }
            model.PicturesStoredIntoDatabase = _pictureService.StoreInDb;
            return View(model);
        }
        [HttpPost]
        [FormValueRequired("save")]
        public ActionResult Media(MediaSettingsModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            //load settings for a chosen site scope
            var siteScope = this.GetActiveSiteScopeConfiguration(_siteService, _workContext);
            var mediaSettings = _settingService.LoadSetting<MediaSettings>(siteScope);
            mediaSettings = model.ToEntity(mediaSettings);

            /* We do not clear cache after each setting update.
             * This behavior can increase performance because cached settings will not be cleared 
             * and loaded from database after each update */
            _settingService.SaveSettingOverridablePerSite(mediaSettings, x => x.AvatarPictureSize, model.AvatarPictureSize_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(mediaSettings, x => x.MaximumImageSize, model.MaximumImageSize_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(mediaSettings, x => x.MultipleThumbDirectories, model.MultipleThumbDirectories_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(mediaSettings, x => x.DefaultImageQuality, model.DefaultImageQuality_OverrideForSite, siteScope, false);
           
            //now clear settings cache
            _settingService.ClearCache();
            
            //activity log
            _userActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings"));

            SuccessNotification(_localizationService.GetResource("Admin.Configuration.Updated"));
            return RedirectToAction("Media");
        }
        [HttpPost, ActionName("Media")]
        [FormValueRequired("change-picture-storage")]
        public ActionResult ChangePictureStorage()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            _pictureService.StoreInDb = !_pictureService.StoreInDb;

            //activity log
            _userActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings"));

            SuccessNotification(_localizationService.GetResource("Admin.Configuration.Updated"));
            return RedirectToAction("Media");
        }



        public ActionResult AllUser()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            var siteScope = this.GetActiveSiteScopeConfiguration(_siteService, _workContext);
            var userSettings = _settingService.LoadSetting<UserSettings>(siteScope);
            var dateTimeSettings = _settingService.LoadSetting<DateTimeSettings>(siteScope);
            var externalAuthenticationSettings = _settingService.LoadSetting<ExternalAuthenticationSettings>(siteScope);

            //merge settings
            var model = new AllUserSettingsModel();
            model.UserSettings = userSettings.ToModel();

            model.DateTimeSettings.AllowUsersToSetTimeZone = dateTimeSettings.AllowUsersToSetTimeZone;
            model.DateTimeSettings.DefaultSiteTimeZoneId = _dateTimeHelper.DefaultSiteTimeZone.Id;
            foreach (TimeZoneInfo timeZone in _dateTimeHelper.GetSystemTimeZones())
            {
                model.DateTimeSettings.AvailableTimeZones.Add(new SelectListItem
                    {
                        Text = timeZone.DisplayName,
                        Value = timeZone.Id,
                        Selected = timeZone.Id.Equals(_dateTimeHelper.DefaultSiteTimeZone.Id, StringComparison.InvariantCultureIgnoreCase)
                    });
            }

            model.ExternalAuthenticationSettings.AutoRegisterEnabled = externalAuthenticationSettings.AutoRegisterEnabled;

            return View(model);
        }
        [HttpPost]
        public ActionResult AllUser(AllUserSettingsModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();


            var siteScope = this.GetActiveSiteScopeConfiguration(_siteService, _workContext);
            var userSettings = _settingService.LoadSetting<UserSettings>(siteScope);
            var dateTimeSettings = _settingService.LoadSetting<DateTimeSettings>(siteScope);
            var externalAuthenticationSettings = _settingService.LoadSetting<ExternalAuthenticationSettings>(siteScope);

            userSettings = model.UserSettings.ToEntity(userSettings);
            _settingService.SaveSetting(userSettings);

            dateTimeSettings.DefaultSiteTimeZoneId = model.DateTimeSettings.DefaultSiteTimeZoneId;
            dateTimeSettings.AllowUsersToSetTimeZone = model.DateTimeSettings.AllowUsersToSetTimeZone;
            _settingService.SaveSetting(dateTimeSettings);

            externalAuthenticationSettings.AutoRegisterEnabled = model.ExternalAuthenticationSettings.AutoRegisterEnabled;
            _settingService.SaveSetting(externalAuthenticationSettings);

            //activity log
            _userActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings"));

            SuccessNotification(_localizationService.GetResource("Admin.Configuration.Updated"));

            //selected tab
            SaveSelectedTabName();

            return RedirectToAction("AllUser");
        }

        
        public ActionResult GeneralCommon()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            //set page timeout to 5 minutes
            this.Server.ScriptTimeout = 300;

            var model = new GeneralCommonSettingsModel();
            var siteScope = this.GetActiveSiteScopeConfiguration(_siteService, _workContext);
            model.ActiveSiteScopeConfiguration = siteScope;
            //site information
            var siteInformationSettings = _settingService.LoadSetting<SiteInformationSettings>(siteScope);
            var commonSettings = _settingService.LoadSetting<CommonSettings>(siteScope);
            model.SiteInformationSettings.SiteClosed = siteInformationSettings.SiteClosed;
            //themes
            model.SiteInformationSettings.DefaultSiteTheme = siteInformationSettings.DefaultSiteTheme;
            model.SiteInformationSettings.AvailableSiteThemes = _themeProvider
                .GetThemeConfigurations()
                .Select(x => new GeneralCommonSettingsModel.SiteInformationSettingsModel.ThemeConfigurationModel
                {
                    ThemeTitle = x.ThemeTitle,
                    ThemeName = x.ThemeName,
                    PreviewImageUrl = x.PreviewImageUrl,
                    PreviewText = x.PreviewText,
                    SupportRtl = x.SupportRtl,
                    Selected = x.ThemeName.Equals(siteInformationSettings.DefaultSiteTheme, StringComparison.InvariantCultureIgnoreCase)
                })
                .ToList();
            model.SiteInformationSettings.AllowUserToSelectTheme = siteInformationSettings.AllowUserToSelectTheme;
            model.SiteInformationSettings.LogoPictureId = siteInformationSettings.LogoPictureId;
            //contact us
            model.SiteInformationSettings.SubjectFieldOnContactUsForm = commonSettings.SubjectFieldOnContactUsForm;
            model.SiteInformationSettings.UseSystemEmailForContactUsForm = commonSettings.UseSystemEmailForContactUsForm;
            //sitemap
            model.SiteInformationSettings.SitemapEnabled = commonSettings.SitemapEnabled;

            //override settings
            if (siteScope > 0)
            {
                model.SiteInformationSettings.SiteClosed_OverrideForSite = _settingService.SettingExists(siteInformationSettings, x => x.SiteClosed, siteScope);
                model.SiteInformationSettings.DefaultSiteTheme_OverrideForSite = _settingService.SettingExists(siteInformationSettings, x => x.DefaultSiteTheme, siteScope);
                model.SiteInformationSettings.AllowUserToSelectTheme_OverrideForSite = _settingService.SettingExists(siteInformationSettings, x => x.AllowUserToSelectTheme, siteScope);
                model.SiteInformationSettings.LogoPictureId_OverrideForSite = _settingService.SettingExists(siteInformationSettings, x => x.LogoPictureId, siteScope);
                model.SiteInformationSettings.SubjectFieldOnContactUsForm_OverrideForSite = _settingService.SettingExists(commonSettings, x => x.SubjectFieldOnContactUsForm, siteScope);
                model.SiteInformationSettings.UseSystemEmailForContactUsForm_OverrideForSite = _settingService.SettingExists(commonSettings, x => x.UseSystemEmailForContactUsForm, siteScope);
                model.SiteInformationSettings.SitemapEnabled_OverrideForSite = _settingService.SettingExists(commonSettings, x => x.SitemapEnabled, siteScope);
              }

            //seo settings
            var seoSettings = _settingService.LoadSetting<SeoSettings>(siteScope);
            model.SeoSettings.PageTitleSeparator = seoSettings.PageTitleSeparator;
            model.SeoSettings.PageTitleSeoAdjustment = (int)seoSettings.PageTitleSeoAdjustment;
            model.SeoSettings.PageTitleSeoAdjustmentValues = seoSettings.PageTitleSeoAdjustment.ToSelectList();
            model.SeoSettings.DefaultTitle = seoSettings.DefaultTitle;
            model.SeoSettings.DefaultMetaKeywords = seoSettings.DefaultMetaKeywords;
            model.SeoSettings.DefaultMetaDescription = seoSettings.DefaultMetaDescription;
            model.SeoSettings.ConvertNonWesternChars = seoSettings.ConvertNonWesternChars;
            model.SeoSettings.CanonicalUrlsEnabled = seoSettings.CanonicalUrlsEnabled;
            model.SeoSettings.WwwRequirement = (int)seoSettings.WwwRequirement;
            model.SeoSettings.WwwRequirementValues = seoSettings.WwwRequirement.ToSelectList();
            model.SeoSettings.EnableJsBundling = seoSettings.EnableJsBundling;
            model.SeoSettings.EnableCssBundling = seoSettings.EnableCssBundling;
            model.SeoSettings.OpenGraphMetaTags = seoSettings.OpenGraphMetaTags;
            model.SeoSettings.CustomHeadTags = seoSettings.CustomHeadTags;
            //override settings
            if (siteScope > 0)
            {
                model.SeoSettings.PageTitleSeparator_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.PageTitleSeparator, siteScope);
                model.SeoSettings.PageTitleSeoAdjustment_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.PageTitleSeoAdjustment, siteScope);
                model.SeoSettings.DefaultTitle_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.DefaultTitle, siteScope);
                model.SeoSettings.DefaultMetaKeywords_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.DefaultMetaKeywords, siteScope);
                model.SeoSettings.DefaultMetaDescription_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.DefaultMetaDescription, siteScope);
                model.SeoSettings.ConvertNonWesternChars_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.ConvertNonWesternChars, siteScope);
                model.SeoSettings.CanonicalUrlsEnabled_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.CanonicalUrlsEnabled, siteScope);
                model.SeoSettings.WwwRequirement_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.WwwRequirement, siteScope);
                model.SeoSettings.EnableJsBundling_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.EnableJsBundling, siteScope);
                model.SeoSettings.EnableCssBundling_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.EnableCssBundling, siteScope);
                model.SeoSettings.OpenGraphMetaTags_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.OpenGraphMetaTags, siteScope);
                model.SeoSettings.CustomHeadTags_OverrideForSite = _settingService.SettingExists(seoSettings, x => x.CustomHeadTags, siteScope);
            }
            
            //security settings
            var securitySettings = _settingService.LoadSetting<SecuritySettings>(siteScope);
            var captchaSettings = _settingService.LoadSetting<CaptchaSettings>(siteScope);
            model.SecuritySettings.EncryptionKey = securitySettings.EncryptionKey;
            if (securitySettings.AdminAreaAllowedIpAddresses != null)
                for (int i = 0; i < securitySettings.AdminAreaAllowedIpAddresses.Count; i++)
                {
                    model.SecuritySettings.AdminAreaAllowedIpAddresses += securitySettings.AdminAreaAllowedIpAddresses[i];
                    if (i != securitySettings.AdminAreaAllowedIpAddresses.Count - 1)
                        model.SecuritySettings.AdminAreaAllowedIpAddresses += ",";
                }
            model.SecuritySettings.ForceSslForAllPages = securitySettings.ForceSslForAllPages;
            model.SecuritySettings.EnableXsrfProtectionForAdminArea = securitySettings.EnableXsrfProtectionForAdminArea;
            model.SecuritySettings.EnableXsrfProtectionForPublicSite = securitySettings.EnableXsrfProtectionForPublicSite;
            model.SecuritySettings.HoneypotEnabled = securitySettings.HoneypotEnabled;
            model.SecuritySettings.CaptchaEnabled = captchaSettings.Enabled;
            model.SecuritySettings.CaptchaShowOnLoginPage = captchaSettings.ShowOnLoginPage;
            model.SecuritySettings.CaptchaShowOnRegistrationPage = captchaSettings.ShowOnRegistrationPage;
            model.SecuritySettings.CaptchaShowOnContactUsPage = captchaSettings.ShowOnContactUsPage;
            model.SecuritySettings.CaptchaShowOnNewsCommentPage = captchaSettings.ShowOnNewsCommentPage;
            model.SecuritySettings.ReCaptchaVersion = captchaSettings.ReCaptchaVersion;
            model.SecuritySettings.AvailableReCaptchaVersions = ReCaptchaVersion.Version1.ToSelectList(false).ToList();
            model.SecuritySettings.ReCaptchaPublicKey = captchaSettings.ReCaptchaPublicKey;
            model.SecuritySettings.ReCaptchaPrivateKey = captchaSettings.ReCaptchaPrivateKey;

            //localization
            var localizationSettings = _settingService.LoadSetting<LocalizationSettings>(siteScope);
            model.LocalizationSettings.UseImagesForLanguageSelection = localizationSettings.UseImagesForLanguageSelection;
            model.LocalizationSettings.SeoFriendlyUrlsForLanguagesEnabled = localizationSettings.SeoFriendlyUrlsForLanguagesEnabled;
            model.LocalizationSettings.AutomaticallyDetectLanguage = localizationSettings.AutomaticallyDetectLanguage;
            model.LocalizationSettings.LoadAllLocaleRecordsOnStartup = localizationSettings.LoadAllLocaleRecordsOnStartup;
            model.LocalizationSettings.LoadAllLocalizedPropertiesOnStartup = localizationSettings.LoadAllLocalizedPropertiesOnStartup;
            model.LocalizationSettings.LoadAllUrlRecordsOnStartup = localizationSettings.LoadAllUrlRecordsOnStartup;

            return View(model);
        }
        [HttpPost]
        [FormValueRequired("save")]
        public ActionResult GeneralCommon(GeneralCommonSettingsModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();


            //load settings for a chosen site scope
            var siteScope = this.GetActiveSiteScopeConfiguration(_siteService, _workContext);

            //site information settings
            var siteInformationSettings = _settingService.LoadSetting<SiteInformationSettings>(siteScope);
            var commonSettings = _settingService.LoadSetting<CommonSettings>(siteScope);
            siteInformationSettings.SiteClosed = model.SiteInformationSettings.SiteClosed;
            siteInformationSettings.DefaultSiteTheme = model.SiteInformationSettings.DefaultSiteTheme;
            siteInformationSettings.AllowUserToSelectTheme = model.SiteInformationSettings.AllowUserToSelectTheme;
            siteInformationSettings.LogoPictureId = model.SiteInformationSettings.LogoPictureId;
            
            //contact us
            commonSettings.SubjectFieldOnContactUsForm = model.SiteInformationSettings.SubjectFieldOnContactUsForm;
            commonSettings.UseSystemEmailForContactUsForm = model.SiteInformationSettings.UseSystemEmailForContactUsForm;
            //sitemap
            commonSettings.SitemapEnabled = model.SiteInformationSettings.SitemapEnabled;

            /* We do not clear cache after each setting update.
             * This behavior can increase performance because cached settings will not be cleared 
             * and loaded from database after each update */

            _settingService.SaveSettingOverridablePerSite(siteInformationSettings, x => x.SiteClosed, model.SiteInformationSettings.SiteClosed_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(siteInformationSettings, x => x.DefaultSiteTheme, model.SiteInformationSettings.DefaultSiteTheme_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(siteInformationSettings, x => x.AllowUserToSelectTheme, model.SiteInformationSettings.AllowUserToSelectTheme_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(siteInformationSettings, x => x.LogoPictureId, model.SiteInformationSettings.LogoPictureId_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(commonSettings, x => x.SubjectFieldOnContactUsForm, model.SiteInformationSettings.SubjectFieldOnContactUsForm_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(commonSettings, x => x.UseSystemEmailForContactUsForm, model.SiteInformationSettings.UseSystemEmailForContactUsForm_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(commonSettings, x => x.SitemapEnabled, model.SiteInformationSettings.SitemapEnabled_OverrideForSite, siteScope, false);

            //now clear settings cache
            _settingService.ClearCache();



            //seo settings
            var seoSettings = _settingService.LoadSetting<SeoSettings>(siteScope);
            seoSettings.PageTitleSeparator = model.SeoSettings.PageTitleSeparator;
            seoSettings.PageTitleSeoAdjustment = (PageTitleSeoAdjustment)model.SeoSettings.PageTitleSeoAdjustment;
            seoSettings.DefaultTitle = model.SeoSettings.DefaultTitle;
            seoSettings.DefaultMetaKeywords = model.SeoSettings.DefaultMetaKeywords;
            seoSettings.DefaultMetaDescription = model.SeoSettings.DefaultMetaDescription;
            seoSettings.ConvertNonWesternChars = model.SeoSettings.ConvertNonWesternChars;
            seoSettings.CanonicalUrlsEnabled = model.SeoSettings.CanonicalUrlsEnabled;
            seoSettings.WwwRequirement = (WwwRequirement)model.SeoSettings.WwwRequirement;
            seoSettings.EnableJsBundling = model.SeoSettings.EnableJsBundling;
            seoSettings.EnableCssBundling = model.SeoSettings.EnableCssBundling;
            seoSettings.OpenGraphMetaTags = model.SeoSettings.OpenGraphMetaTags;
            seoSettings.CustomHeadTags = model.SeoSettings.CustomHeadTags;

            /* We do not clear cache after each setting update.
             * This behavior can increase performance because cached settings will not be cleared 
             * and loaded from database after each update */
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.PageTitleSeparator, model.SeoSettings.PageTitleSeparator_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.PageTitleSeoAdjustment, model.SeoSettings.PageTitleSeoAdjustment_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.DefaultTitle, model.SeoSettings.DefaultTitle_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.DefaultMetaKeywords, model.SeoSettings.DefaultMetaKeywords_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.DefaultMetaDescription, model.SeoSettings.DefaultMetaDescription_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.ConvertNonWesternChars, model.SeoSettings.ConvertNonWesternChars_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.CanonicalUrlsEnabled, model.SeoSettings.CanonicalUrlsEnabled_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.WwwRequirement, model.SeoSettings.WwwRequirement_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.EnableJsBundling, model.SeoSettings.EnableJsBundling_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.EnableCssBundling, model.SeoSettings.EnableCssBundling_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.OpenGraphMetaTags, model.SeoSettings.OpenGraphMetaTags_OverrideForSite, siteScope, false);
            _settingService.SaveSettingOverridablePerSite(seoSettings, x => x.CustomHeadTags, model.SeoSettings.CustomHeadTags_OverrideForSite, siteScope, false);
            
            //now clear settings cache
            _settingService.ClearCache();



            //security settings
            var securitySettings = _settingService.LoadSetting<SecuritySettings>(siteScope);
            var captchaSettings = _settingService.LoadSetting<CaptchaSettings>(siteScope);
            if (securitySettings.AdminAreaAllowedIpAddresses == null)
                securitySettings.AdminAreaAllowedIpAddresses = new List<string>();
            securitySettings.AdminAreaAllowedIpAddresses.Clear();
            if (!String.IsNullOrEmpty(model.SecuritySettings.AdminAreaAllowedIpAddresses))
                foreach (string s in model.SecuritySettings.AdminAreaAllowedIpAddresses.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                    if (!String.IsNullOrWhiteSpace(s))
                        securitySettings.AdminAreaAllowedIpAddresses.Add(s.Trim());
            securitySettings.ForceSslForAllPages = model.SecuritySettings.ForceSslForAllPages;
            securitySettings.EnableXsrfProtectionForAdminArea = model.SecuritySettings.EnableXsrfProtectionForAdminArea;
            securitySettings.EnableXsrfProtectionForPublicSite = model.SecuritySettings.EnableXsrfProtectionForPublicSite;
            securitySettings.HoneypotEnabled = model.SecuritySettings.HoneypotEnabled;
            _settingService.SaveSetting(securitySettings);
            captchaSettings.Enabled = model.SecuritySettings.CaptchaEnabled;
            captchaSettings.ShowOnLoginPage = model.SecuritySettings.CaptchaShowOnLoginPage;
            captchaSettings.ShowOnRegistrationPage = model.SecuritySettings.CaptchaShowOnRegistrationPage;
            captchaSettings.ShowOnContactUsPage = model.SecuritySettings.CaptchaShowOnContactUsPage;
            captchaSettings.ShowOnNewsCommentPage = model.SecuritySettings.CaptchaShowOnNewsCommentPage;
            captchaSettings.ReCaptchaVersion = model.SecuritySettings.ReCaptchaVersion;
            captchaSettings.ReCaptchaPublicKey = model.SecuritySettings.ReCaptchaPublicKey;
            captchaSettings.ReCaptchaPrivateKey = model.SecuritySettings.ReCaptchaPrivateKey;
            _settingService.SaveSetting(captchaSettings);
            if (captchaSettings.Enabled &&
                (String.IsNullOrWhiteSpace(captchaSettings.ReCaptchaPublicKey) || String.IsNullOrWhiteSpace(captchaSettings.ReCaptchaPrivateKey)))
            {
                //captcha is enabled but the keys are not entered
                ErrorNotification("Captcha is enabled but the appropriate keys are not entered");
            }

            //now clear settings cache
            _settingService.ClearCache();




            //localization settings
            var localizationSettings = _settingService.LoadSetting<LocalizationSettings>(siteScope);
            localizationSettings.UseImagesForLanguageSelection = model.LocalizationSettings.UseImagesForLanguageSelection;
            if (localizationSettings.SeoFriendlyUrlsForLanguagesEnabled != model.LocalizationSettings.SeoFriendlyUrlsForLanguagesEnabled)
            {
                localizationSettings.SeoFriendlyUrlsForLanguagesEnabled = model.LocalizationSettings.SeoFriendlyUrlsForLanguagesEnabled;
                //clear cached values of routes
                System.Web.Routing.RouteTable.Routes.ClearSeoFriendlyUrlsCachedValueForRoutes();
            }
            localizationSettings.AutomaticallyDetectLanguage = model.LocalizationSettings.AutomaticallyDetectLanguage;
            localizationSettings.LoadAllLocaleRecordsOnStartup = model.LocalizationSettings.LoadAllLocaleRecordsOnStartup;
            localizationSettings.LoadAllLocalizedPropertiesOnStartup = model.LocalizationSettings.LoadAllLocalizedPropertiesOnStartup;
            localizationSettings.LoadAllUrlRecordsOnStartup = model.LocalizationSettings.LoadAllUrlRecordsOnStartup;
            _settingService.SaveSetting(localizationSettings);

            //activity log
            _userActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings"));

            SuccessNotification(_localizationService.GetResource("Admin.Configuration.Updated"));
            
            return RedirectToAction("GeneralCommon");
        }
        [HttpPost, ActionName("GeneralCommon")]
        [FormValueRequired("changeencryptionkey")]
        public ActionResult ChangeEncryptionKey(GeneralCommonSettingsModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            //set page timeout to 5 minutes
            this.Server.ScriptTimeout = 300;

            var siteScope = this.GetActiveSiteScopeConfiguration(_siteService, _workContext);
            var securitySettings = _settingService.LoadSetting<SecuritySettings>(siteScope);

            try
            {
                if (model.SecuritySettings.EncryptionKey == null)
                    model.SecuritySettings.EncryptionKey = "";

                model.SecuritySettings.EncryptionKey = model.SecuritySettings.EncryptionKey.Trim();

                var newEncryptionPrivateKey = model.SecuritySettings.EncryptionKey;
                if (String.IsNullOrEmpty(newEncryptionPrivateKey) || newEncryptionPrivateKey.Length != 16)
                    throw new AppException(_localizationService.GetResource("Admin.Configuration.Settings.GeneralCommon.EncryptionKey.TooShort"));

                string oldEncryptionPrivateKey = securitySettings.EncryptionKey;
                if (oldEncryptionPrivateKey == newEncryptionPrivateKey)
                    throw new AppException(_localizationService.GetResource("Admin.Configuration.Settings.GeneralCommon.EncryptionKey.TheSame"));
                
                //update user information
                //optimization - load only users with PasswordFormat.Encrypted
                var users = _userService.GetAllUsersByPasswordFormat(PasswordFormat.Encrypted);
                foreach (var user in users)
                {
                    string decryptedPassword = _encryptionService.DecryptText(user.Password, oldEncryptionPrivateKey);
                    string encryptedPassword = _encryptionService.EncryptText(decryptedPassword, newEncryptionPrivateKey);

                    user.Password = encryptedPassword;
                    _userService.UpdateUser(user);
                }

                securitySettings.EncryptionKey = newEncryptionPrivateKey;
                _settingService.SaveSetting(securitySettings);
                SuccessNotification(_localizationService.GetResource("Admin.Configuration.Settings.GeneralCommon.EncryptionKey.Changed"));
            }
            catch (Exception exc)
            {
                ErrorNotification(exc);
            }
            return RedirectToAction("GeneralCommon");
        }
        
        //all settings
        public ActionResult AllSettings()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();
            
            return View();
        }
        [HttpPost]
        //do not validate request token (XSRF)
        //for some reasons it does not work with "filtering" support
        [AdminAntiForgery(true)] 
        public ActionResult AllSettings(DataSourceRequest command, AllSettingsListModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            var query = _settingService.GetAllSettings().AsQueryable();

            if (!string.IsNullOrEmpty(model.SearchSettingName))
                query = query.Where(s => s.Name.ToLowerInvariant().Contains(model.SearchSettingName.ToLowerInvariant()));
            if (!string.IsNullOrEmpty(model.SearchSettingValue))
                query = query.Where(s => s.Value.ToLowerInvariant().Contains(model.SearchSettingValue.ToLowerInvariant()));

            var settings = query.ToList()
                .Select(x =>
                            {
                                string siteName;
                                if (x.SiteId == 0)
                                {
                                    siteName = _localizationService.GetResource("Admin.Configuration.Settings.AllSettings.Fields.SiteName.AllSites");
                                }
                                else
                                {
                                    var site = _siteService.GetSiteById(x.SiteId);
                                    siteName = site != null ? site.Name : "Unknown";
                                }
                                var settingModel = new SettingModel
                                {
                                    Id = x.Id,
                                    Name = x.Name,
                                    Value = x.Value,
                                    Site = siteName,
                                    SiteId = x.SiteId
                                };
                                return settingModel;
                            })
                .AsQueryable();

            var gridModel = new DataSourceResult
            {
                Data = settings.PagedForCommand(command).ToList(),
                Total = settings.Count()
            };

            return Json(gridModel);
        }
        [HttpPost]
        public ActionResult SettingUpdate(SettingModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            if (model.Name != null)
                model.Name = model.Name.Trim();
            if (model.Value != null)
                model.Value = model.Value.Trim();

            if (!ModelState.IsValid)
            {
                return Json(new DataSourceResult { Errors = ModelState.SerializeErrors() });
            }

            var setting = _settingService.GetSettingById(model.Id);
            if (setting == null)
                return Content("No setting could be loaded with the specified ID");

            var siteId = model.SiteId;

            if (!setting.Name.Equals(model.Name, StringComparison.InvariantCultureIgnoreCase) ||
                setting.SiteId != siteId)
            {
                //setting name or site has been changed
                _settingService.DeleteSetting(setting);
            }

            _settingService.SetSetting(model.Name, model.Value, siteId);

            //activity log
            _userActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings"));

            return new NullJsonResult();
        }
        [HttpPost]
        public ActionResult SettingAdd([Bind(Exclude = "Id")] SettingModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            if (model.Name != null)
                model.Name = model.Name.Trim();
            if (model.Value != null)
                model.Value = model.Value.Trim();

            if (!ModelState.IsValid)
            {
                return Json(new DataSourceResult { Errors = ModelState.SerializeErrors() });
            }
            var siteId = model.SiteId;
            _settingService.SetSetting(model.Name, model.Value, siteId);

            //activity log
            _userActivityService.InsertActivity("AddNewSetting", _localizationService.GetResource("ActivityLog.AddNewSetting"), model.Name);

            return new NullJsonResult();
        }
        [HttpPost]
        public ActionResult SettingDelete(int id)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return AccessDeniedView();

            var setting = _settingService.GetSettingById(id);
            if (setting == null)
                throw new ArgumentException("No setting found with the specified id");
            _settingService.DeleteSetting(setting);

            //activity log
            _userActivityService.InsertActivity("DeleteSetting", _localizationService.GetResource("ActivityLog.DeleteSetting"), setting.Name);

            return new NullJsonResult();
        }

        #endregion
    }
}
